/*******************************************************************************
 *	                           bsp os.c
 *******************************************************************************/
#include "bsp.h"
#include "os_obj.h"
#include "mytype.h"

#define UDC_RX_IDLE 0
#define UDC_RX_RCV 1
#define UDC_RX_END 2
#define UDC_RX_TOUT 3

#define UDC_TX_IDLE 0
#define UDC_TX_REQ 1
#define UDC_TX_BUSY 2

typedef struct
{
	uu8 *buff;
	uu8 len;
} udc_tx_list_type;

typedef struct
{
	uu8 rx_st;
	uu8 tx_st;

	uu8 rx_cnt;
	uu8 rx_buff_size;
	uu8 tx_cnt;

	uu8 tx_size;
	uu8 tx_buff_size;

	// rx end time
	uu8 rx_et_cnt;
	uu8 rx_et_sv;

	// rx timeout
	uu8 rx_ot_cnt;
	uu8 rx_ot_sv;

	// tx idle time
	uu8 tx_idle_cnt;
	uu8 tx_idle_sv;

	// buff
	uu8 *rx_buff;
	uu8 *tx_buff;

	udc_tx_list_type *tx_list;
	uu8 tx_list_size;
	uu8 tx_list_site;

	// callback
	void (*os_event_send)(uu16 event);
	void (*tx_send)(void);
	void (*tx_dat_get)(uu8 **pbuff, uu8 *plen);
	void (*rx_handle)(uu8 *buff, uu8 len);
} udcom_type;

/*******************************************************************************
 * @brief  os_isr_entry
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void udc_timer_handle(udcom_type *obj)
{
	switch (obj->rx_st)
	{
	case UDC_RX_IDLE:
		obj->rx_ot_cnt++;
		if (obj->rx_ot_cnt >= obj->rx_ot_sv)
		{
			obj->rx_ot_cnt = 0;
			obj->rx_st = UDC_RX_TOUT;
			if (obj->os_event_send)
				obj->os_event_send(1 << 0);
		}
		break;
	case UDC_RX_RCV:
		obj->rx_et_cnt++;
		if (obj->rx_et_cnt >= obj->rx_et_sv)
		{
			obj->rx_et_cnt = 0;
			obj->rx_st = UDC_RX_END;
			if (obj->os_event_send)
				obj->os_event_send(1 << 1);
		}
		break;
	case UDC_RX_END:
		break;
	case UDC_RX_TOUT:
		break;
	default:
		obj->rx_st = UDC_RX_IDLE;
		break;
	}

	switch (obj->tx_st)
	{
	case UDC_TX_IDLE:
		obj->tx_idle_cnt++;
		if (obj->tx_idle_cnt >= obj->tx_idle_sv)
		{
			obj->tx_idle_cnt = 0;
			obj->tx_st = UDC_TX_REQ;
			if (obj->os_event_send)
				obj->os_event_send(1 << 4);
		}
		break;
	case UDC_TX_REQ:
		break;
	case UDC_TX_BUSY:
		break;
	default:
		obj->rx_st = UDC_TX_IDLE;
		break;
	}
}

/*******************************************************************************
 * @brief  os_isr_exit
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void udc_poll(udcom_type *obj)
{
	switch (obj->rx_st)
	{
	case UDC_RX_IDLE:
		break;
	case UDC_RX_RCV:

	case UDC_RX_END:
		obj->rx_handle(obj->rx_buff, obj->rx_cnt);
		obj->rx_st = UDC_RX_IDLE;
		break;
	case UDC_RX_TOUT:
		break;
	default:
		obj->rx_st = UDC_RX_IDLE;
		break;
	}

	switch (obj->tx_st)
	{
	case UDC_TX_IDLE:
		break;
	case UDC_TX_REQ:
	{
		uu8 *pbuff, len, tx_size;

		obj->tx_dat_get(&pbuff, &len);
		if (len > 0)
		{
			tx_size = 0;
			loop(len)
			{
				if (tx_size < obj->tx_buff_size)
					obj->tx_buff[tx_size++] = *pbuff++;
				else
					break;
			}
			obj->tx_size = tx_size;
			obj->tx_cnt = 0;
			obj->tx_st = UDC_TX_BUSY;
			obj->tx_send();
		}
		break;
	}
	case UDC_TX_BUSY:
		break;
	default:
		obj->rx_st = UDC_TX_IDLE;
		break;
	}
}
